<template>
  <el-upload v-loading="loading" action="" class="ml-upload-image" drag element-loading-text="上传中"
    accept=".jpg,.jpeg,.png,.gif,.bmp,.JPG,.JPEG,.PBG,.GIF,.BMP" :auto-upload="false" :show-file-list="false"
    :on-change="eventChange" :style="`${custom ? '' : `height:${width};width:${width};`}`"
    @mouseenter.native="show_delete = true" @mouseleave.native="show_delete = false">
    <template v-if="img">
      <!--  预览   -->
      <el-image :src="(img || '')" class="preview-img">
        <div slot="error" class="image-slot" style="line-height: 2">
          暂无<br>图片
        </div>
      </el-image>
      <div v-if="show_delete" class="delete_mark" @click.stop="handleDelete">
        <span>删除</span>
      </div>
    </template>
    <slot v-else-if="custom" />
    <i v-else class="el-icon-plus avatar-uploader-icon" />
  </el-upload>
</template>
<script>
import request from '@/utils/request'

export default {
  name: 'MlUploadImage',
  props: {
    // eslint-disable-next-line vue/require-default-prop
    id: [String, Number],
    // eslint-disable-next-line vue/require-default-prop
    url: String,
    width: {
      type: String,
      default() {
        return '100px'
      }
    },
    custom: Boolean
  },
  data() {
    return {
      loading: false,
      img: null,
      img_id: null,
      img_url: null,
      show_delete: false
    }
  },
  watch: {
    img_id: function (_) {
      this.$emit('update:id', _)
    },
    url: {
      handler: function (_) {
        this.img = _
      },
      immediate: true
    }
  },
  methods: {
    handleDelete: function () {
      this.img = null
      this.img_id = null
      this.$emit('delete', this.id ?? '')
      this.$emit('update:id', null)
      this.$emit('update:url', null)
    },
    /**
     * 图片上传事件
     * @param file
     * @returns {Promise<void>}
     */
    eventChange: async function (file) {
      this.loading = true

      // todo 压缩图片文件
      const file_new = await this.compressFile(file.raw, 0.8)
      // todo 请求后端
      const is_success = await this.handleUpload(file_new)

      if (is_success) {
        this.img = URL.createObjectURL(file_new)
        this.$emit('success', { id: this.img_id, src: this.img_url })
      } else {
        this.img = null
        this.img_id = null
        this.img_url = null
      }

      this.$emit('update:url', this.img_url)
      this.loading = false
    },
    /**
     * todo 请求后端上传接口
     * @param file
     * @returns {Promise<boolean>}
     */
    handleUpload: async function (file) {
      const data = new FormData()
      data.append('file', file)
      // const { data: result } = await uploadFile(data)
      const res = await request({
        url: '/admin/common/uploadFile',
        method: 'post',
        data
      })
      // console.log(res);
      if(res.code == 200) {
        this.img_id = res.result.id
        this.img_url = `${res.result.url}` + `${res.result.path}`
        return true
      }else {
        return false
      }
    },
    /**
     * 压缩图片
     * @param file 压缩文件
     * @param compressThreshold 开启压缩的阈值，默认 5M
     * @param openCompress 是否开启压缩，默认 true
     * @param pictureQuality 压缩比，默认 0.92
     * @returns
     */
    compressFile: function (file, compressThreshold = 5, openCompress = true, pictureQuality = 0.92) {
      // console.log('========== Entry Compress File Function ==========')
      // 判断是否是图片类型
      const isAccept = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'].includes(file.type)
      if (isAccept) {
        const fileSize = file.size / 1024 / 1024
        // console.log('before compress, the file size is : ', fileSize.toFixed(2) + ' M')
        // 当开启图片压缩且图片大小大于等于压缩阈值,进行压缩
        if (fileSize >= compressThreshold && openCompress) {
          // 判断浏览器内核是否支持base64图片压缩
          if (typeof FileReader === 'undefined') {
            return file
          } else {
            try {
              return new Promise(resolve => {
                // 声明FileReader文件读取对象
                const reader = new FileReader()
                reader.readAsDataURL(file)
                reader.onload = () => {
                  // 生成canvas画布
                  const canvas = document.createElement('canvas')
                  // 生成img
                  // const img = document.createElement('img');
                  const img = new Image()
                  img.src = reader.result
                  img.onload = () => {
                    const ctx = canvas.getContext('2d')
                    // 原始图片宽度、高度
                    const originImageWidth = img.width
                    const originImageHeight = img.height
                    // 默认最大尺度的尺寸限制在（1920 * 1080）
                    const maxWidth = 1920
                    const maxHeight = 1080
                    const ratio = maxWidth / maxHeight
                    // 目标尺寸
                    let targetWidth = originImageWidth
                    let targetHeight = originImageHeight
                    // 当图片的宽度或者高度大于指定的最大宽度或者最大高度时,进行缩放图片
                    if (originImageWidth > maxWidth || originImageHeight > maxHeight) {
                      // 超过最大宽高比例
                      if (originImageWidth / originImageHeight > ratio) {
                        // 宽度取最大宽度值maxWidth,缩放高度
                        targetWidth = maxWidth
                        targetHeight = Math.round(maxWidth * (originImageHeight / originImageWidth))
                      } else {
                        // 高度取最大高度值maxHeight,缩放宽度
                        targetHeight = maxHeight
                        targetWidth = Math.round(maxHeight * (originImageWidth / originImageHeight))
                      }
                    }
                    // canvas对图片进行缩放
                    canvas.width = targetWidth
                    canvas.height = targetHeight
                    // 清除画布
                    ctx?.clearRect(0, 0, targetWidth, targetHeight)
                    // 绘制图片
                    ctx?.drawImage(img, 0, 0, targetWidth, targetHeight)
                    // quality值越小,图像越模糊,默认图片质量为0.92
                    const imageDataURL = canvas.toDataURL(file.type || 'image/jpeg', pictureQuality)
                    // 去掉URL的头,并转换为byte
                    const imageBytes = window.atob(imageDataURL.split(',')[1])
                    // 处理异常,将ascii码小于0的转换为大于0
                    const arrayBuffer = new ArrayBuffer(imageBytes.length)
                    const uint8Array = new Uint8Array(arrayBuffer)
                    for (let i = 0; i < imageBytes.length; i++) {
                      uint8Array[i] = imageBytes.charCodeAt(i)
                    }
                    const mimeType = imageDataURL?.split(',')?.[0]?.match(/:(.*?);/)?.[1]
                    const newFile = new File([uint8Array], file.name, {
                      type: mimeType || 'image/jpeg'
                    })
                    // console.log(
                    //   'after compress, the file size is : ',
                    //   (newFile.size / 1024 / 1024).toFixed(2) + 'M'
                    // )
                    // console.log('after compress file: ', newFile)
                    resolve(newFile)
                  }
                }
                reader.onerror = () => {
                  return file
                }
              })
                .then(res => {
                  return res
                })
                .catch(() => {
                  return file
                })
            } catch (e) {
              // 压缩出错,直接返回原file对象
              return file
            }
          }
        } else {
          // 不需要压缩，直接返回原file对象
          return file
        }
      } else {
        // 非图片文件,不进行压缩,直接返回原file对象

        return file
      }
    }
  }
}
</script>
<style lang='scss'>
.ml-upload-image {
  position: relative;

  .el-upload,
  .el-upload-dragger {
    width: 100% !important;
    height: 100% !important;
  }

  .el-upload-dragger {
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .preview-img {
    max-width: 100%;
    max-height: 100%;
    vertical-align: middle;

  }

  .delete_mark {
    position: absolute;
    width: 100%;
    height: 50px;
    background: #111;
    opacity: .7;
    bottom: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    border-radius: 4px;

    span {
      color: #FFFFFF;
      cursor: pointer;
      font-size: 14px;
    }
  }
}
</style>
